#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <functional>

using namespace std;

// RAII锁管理类
template <class Lock>
class LockGuard
{
public:
    LockGuard(Lock &lck)
        : _lck(lck)
    {
        _lck.lock();
    }

    ~LockGuard()
    {
        _lck.unlock();
    }

private:
    Lock &_lck; // 锁的引用，锁不允许拷贝！
};
class InFoSingleton
{
public:
    static InFoSingleton &GetINstance()
    {
        LockGuard<mutex> lock(_smtx);
        if (_psins == nullptr)
        {
            _psins = new InFoSingleton;
        }
        return *_psins;
    }
    //	// 一般单例对象不需要考虑释放
    //	// 单例对象不用时，必须手动处理，一些资源需要保存
    //	// 可以手动调用主动回收
    //	// 也可以让他自己在程序结束时，自动回收
    static void Delinstance()
    {
        //....保存数据
        LockGuard<mutex> lock(_smtx); // 保存数据需要加锁就加上，不需要就不加
        if (_psins)
        {
            delete _psins;
            _psins = nullptr;
        }
    }
    // 也可以让他自己在程序结束时，自动回收
    class GC
    {
    public:
        ~GC() // 帮助我们带走资源
        {
            if (_psins) // 如果我们手动释放了，GC就不调用Delinstance()。如果我们没有释放GC帮我们掉该函数
            {
                cout << "~GC()" << endl;
                Delinstance(); // 内部类是外部类的友元
            }
        }
    };
    void insert(string name, int money)
    {
        _info[name] = money;
    }
    void Print()
    {
        for (auto &e : _info)
        {
            cout << e.first << ":" << e.second << endl;
        }
        cout << endl;
    }

private:
    InFoSingleton()
    {
    }
    InFoSingleton(const InFoSingleton &) = delete;
    InFoSingleton &operator=(const InFoSingleton &) = delete;

    map<string, int> _info;

private:
    static InFoSingleton *_psins;
    static mutex _smtx;
    static GC _gc;
};
InFoSingleton *InFoSingleton::_psins = nullptr;
mutex InFoSingleton::_smtx;
InFoSingleton::GC InFoSingleton::_gc; // 定义一个GC对象，出了作用域也就是main函数销毁了，自动调用析构函数

int main()
{
    InFoSingleton::GetINstance().insert("张三", 10000);
    InFoSingleton::GetINstance().insert("李四", 8000);
    InFoSingleton &p1 = InFoSingleton::GetINstance();
    p1.insert("王五", 5000);
    p1.insert("赵六", 3000);
    p1.Print();
    p1.Delinstance();
    return 0;
}

// //////------ 单例模式 ： 饿汉模式
// class InFoSingleton
// {
// public:
//     static InFoSingleton &GetINstance()
//     {
//         return _sins;
//     }
//     void insert(string name, int money)
//     {
//         _info[name] = money;
//     }
//     void Print()
//     {
//         for (auto &e : _info)
//         {
//             cout << e.first << ":" << e.second << endl;
//         }
//         cout << endl;
//     }

// private:
//     InFoSingleton()
//     {
//     }
//     InFoSingleton(const InFoSingleton &) = delete;
//     InFoSingleton &operator=(const InFoSingleton &) = delete;

//     map<string, int> _info;

// private:
//     static InFoSingleton _sins; // 声明
// };
// //_sins与全局变量没什么区别，只是_sins属于InFoSingleton类域
// // 而优点就是InFoSingleton类域里面的全局变量可以调用成员函数
// InFoSingleton InFoSingleton::_sins; // 定义
// // 前面的是_sins的类型，后面的是_sins所在的类域

// int main()
// {
//     InFoSingleton::GetINstance().insert("张三", 10000); // 只有一个对象p1
//     InFoSingleton::GetINstance().insert("李四", 8000);
//     InFoSingleton &p1 = InFoSingleton::GetINstance();
//     p1.insert("王五", 5000);
//     p1.insert("赵六", 3000);
//     p1.Print();

//     InFoSingleton &p2 = InFoSingleton::GetINstance();
//     p2.insert("王五", 5000);
//     p2.insert("赵六", 3000);
//     p2.Print();
//     // InFoSingleton copy = InFoSingleton::GetINstance();//拷贝构造要禁止，不然就产生两个对象了
//     // copy.insert("孙七", 15000);
//     // copy.Print();
//     return 0;
// }

// class StackOnly
// {
// public:
//     static StackOnly creatobj()
//     {
//         return StackOnly();
//     }
//     // void* operator new(size_t size) = delete;//这种方法只能禁止new，不能够禁止static StackOnly s2
//     // void operator delete(void* p) = delete;
// private:
//     StackOnly()
//     {
//     }
//     // StackOnly(const StackOnly&) = delete;这里封掉拷贝构造下面的s1也不能构建对象了
// };
// int main()
// {

//     StackOnly s1 = StackOnly::creatobj();

//     // static StackOnly s2;//把下面种方法禁掉
//     // StackOnly* s3 = new StackOnly;

//     static StackOnly s4 = StackOnly::creatobj(); // 静态区创建对象
//     // 这种方法没有办法解决，只能避免使用
//     return 0;
// }

// // 只能在堆上创建对象的类
// class HeapOnly
// {
// public:
//     HeapOnly()
//     {
//         cout << "调用构造函数"  << endl;
//     }
//     // static void Destory(HeapOnly* p)
//     //{
//     //	p->~HeapOnly();
//     // }
//     void Destory() // 调用析构函数就表示有对象了，不用加static
//     {
//         this->~HeapOnly();
//     }

// private:
//     ~HeapOnly() // 封掉析构函数
//     {
//     }

//     HeapOnly(const HeapOnly &) = delete; // 禁止拷贝构造 —— 防拷贝
// };

// int main()
// {
//     // HeapOnly h1;
//     HeapOnly *h = new HeapOnly;
//     // delete h;

//     // HeapOnly::Destory(h);
//     h->Destory();
//     return 0;
// }

// // 只能在堆上创建对象的类
// class HeapOnly
// {
// public:
//     // HeapOnly* CreateObj()//想调这个函数要有对象，但是要想有一个对象要掉这个函数
//     //{
//     //	return new HeapOnly;
//     // }
//     static HeapOnly *CreateObj() // 静态函数没有this指针,可以被调用
//     {
//         cout << "new hello" << endl;
//         return new HeapOnly;
//     }

// private:
//     HeapOnly()
//     {
//     }

//     HeapOnly(const HeapOnly &) = delete; // 禁止拷贝构造 —— 防拷贝
// };

// int main()
// {
//     // HeapOnly h1;
//     // HeapOnly* h2 = new HeapOnly;
//     // static HeapOnly h3;

//     HeapOnly *h4 = HeapOnly::CreateObj();
//     // HeapOnly h5(* h4);//防拷贝
//     return 0;
// }

// class A
// {

// public:
//     void test1();

// private:
//     void test2();
// };
// void A::test1()
// {
//     cout << "hello AAA" << endl;
// }
// void A::test2()
// {
//     cout << "hello BBB" << endl;
// }
// int main()
// {
//     A a;
//     a.test1();
//     // a.test2();
//     return 0;
// }